/*
** uncomp.c
**
** Pictor, Version 1.51, Copyright (c) 1992-94 SoftCircuits
** Redistributed by permission.
*/

#include <stdlib.h>
#include "compress.h"


/* variable declarations */
static BYTE *buffer;
static WORD index;
static BYTE curr_bit;


/*
** Returns the next available bit value from buffer.
*/
static BYTE read_bit(void)
{
	BYTE bit;

	if(curr_bit == 0) {
		index++;
		curr_bit = 1;
	}

	bit = (BYTE)((buffer[index] & curr_bit) ? 1 : 0);

	curr_bit <<= 1;

	return(bit);

} /* read_bit */

/*
** Uncompresses a compressed buffer. len specifies the
** uncompressed length.
*/
void uncompress(BYTE *in_array,WORD len,BYTE *out_array,NODE *root)
{
	WORD i;
	NODE *node_ptr;

	buffer = in_array;   /* set variables for read_bit() */
	index = 0;
	curr_bit = 1;

	for(i = 0;i < len;i++) {
		node_ptr = root;
		while(node_ptr->child0 != NULL) {
			if(read_bit() == 0) {
				node_ptr = node_ptr->child0;
			}
			else {
				node_ptr = node_ptr->child1;
			}
		}
		out_array[i] = node_ptr->c;
	}

} /* uncompress */

/*
** Combines two child nodes into a single branch node and returns a
** pointer to the branch. NULL indicates memory error.
*/
static NODE *build_branch(NODE *child0,NODE *child1)
{
	NODE *node_ptr;

	node_ptr = malloc(sizeof(NODE));
	if(node_ptr != NULL) {
		node_ptr->child0 = child0;
		node_ptr->child1 = child1;
	}
	else {
		freetree(child0);
		freetree(child1);
	}
	return(node_ptr);

} /* build_branch */

/*
** Recursive portion of readtree().
**
** This function takes care that all memory gets freed upon failure.
*/
static NODE *_readtree(void)
{
	NODE *node_ptr,*child0,*child1;
	int i;

	if(read_bit() == 1) {
		child0 = _readtree();
		if(child0 == NULL)
			return(NULL);
		child1 = _readtree();
		if(child1 == NULL) {
			freetree(child0);
			return(NULL);
		}
		node_ptr = build_branch(child0,child1);
	}
	else {
		node_ptr = malloc(sizeof(NODE));
		if(node_ptr != NULL) {
			for(node_ptr->c = 0,i = 0;i < 8;i++)
				node_ptr->c |= (read_bit() << i);
			node_ptr->child0 = NULL;
			node_ptr->child1 = NULL;
		}
	}
	return(node_ptr);

} /* _readtree */

/*
** Constructs a code tree from in_array and returns a pointer to
** the root node, NULL indicates memory error.
*/
NODE *readtree(BYTE *in_array)
{
	buffer = in_array;   /* set variables for read_bit() */
	index = 0;
	curr_bit = 1;

	return(_readtree());

} /* readtree */
